﻿using System;
using System.Collections.Generic;
using System.Linq;

namespace Cms.Domain
{
    [Serializable]
    public class MediaFile : ICloneable, IComparable<MediaFile>, IAuditable
    {
        private IList<AdministratorGroup> _allowedAdministratorGroups;
        private IList<Category> _categories;
        private IList<AdministratorGroup> _deniedAdministratorGroups;
        private IList<UserGroup> _deselectedUserGroups;
        private DateTime? _endPublishing;
        private string _extension;
        private MediaFolder _folder;
        private int _id;
        private IDictionary<int, MediaFileLocalizedProperties> _localizedProperties;
        private string _name;
        private IList<UserGroup> _requiredUserGroups;
        private Site _site;
        private long _size;
        private string _sortKey;
        private DateTime? _startPublishing;
        private DateTime _uploadedTimestamp;
        private string _version;

        public MediaFile()
        {
            _version = DateTime.Now.Ticks.ToString();
            _uploadedTimestamp = DateTime.Now;
            _categories = new List<Category>();
            _localizedProperties = new Dictionary<int, MediaFileLocalizedProperties>();
            _allowedAdministratorGroups = new List<AdministratorGroup>();
            _deniedAdministratorGroups = new List<AdministratorGroup>();
            _requiredUserGroups = new List<UserGroup>();
            _deselectedUserGroups = new List<UserGroup>();
        }

        public MediaFile(MediaFile file)
            : this()
        {
            _name = file.Name;
            _site = file.Site;
            _site.MediaFiles.Add(this);
            _extension = file.Extension;
            _size = file.Size;
            _uploadedTimestamp = file.UploadedTimestamp;
            _startPublishing = file.StartPublishing;
            _endPublishing = file.EndPublishing;
            _sortKey = file.SortKey;
            foreach (var kvp in file.LocalizedProperties)
            {
                _localizedProperties.Add(kvp.Key, (MediaFileLocalizedProperties)kvp.Value.Clone());
            }
        }

        public virtual int ID
        {
            get { return _id; }
            set { _id = value; }
        }
        
        public virtual string Name
        {
            get { return _name; }
            set { _name = value; }
        }
        
        public virtual MediaFolder Folder
        {
            get { return _folder; }
            set { _folder = value; }
        }
        
        public virtual Site Site
        {
            get { return _site; }
            set { _site = value; }
        }

        public virtual string Extension
        {
            get { return _extension; }
            set { _extension = value; }
        }
        
        public virtual string Version
        {
            get { return _version; }
            set { _version = value; }
        }

        public virtual long Size
        {
            get { return _size; }
            set { _size = value; }
        }

        public virtual DateTime UploadedTimestamp
        {
            get { return _uploadedTimestamp; }
            set { _uploadedTimestamp = value; }
        }
        
        public virtual DateTime? StartPublishing
        {
            get { return _startPublishing; }
            set { _startPublishing = value; }
        }

        public virtual DateTime? EndPublishing
        {
            get { return _endPublishing; }
            set { _endPublishing = value; }
        }
        
        public virtual IList<Category> Categories
        {
            get { return _categories; }
            set { _categories = value; }
        }

        public virtual string SortKey
        {
            get { return _sortKey; }
            set { _sortKey = value; }
        }
        
        public virtual IDictionary<int, MediaFileLocalizedProperties> LocalizedProperties
        {
            get { return _localizedProperties; }
            set { _localizedProperties = value; }
        }

        public virtual IList<AdministratorGroup> AllowedAdministratorGroups
        {
            get { return _allowedAdministratorGroups; }
            set { _allowedAdministratorGroups = value; }
        }

        public virtual IList<AdministratorGroup> DeniedAdministratorGroups
        {
            get { return _deniedAdministratorGroups; }
            set { _deniedAdministratorGroups = value; }
        }
        
        public virtual IList<UserGroup> RequiredUserGroups
        {
            get { return _requiredUserGroups; }
            set { _requiredUserGroups = value; }
        }

        public virtual IList<UserGroup> DeselectedUserGroups
        {
            get { return _deselectedUserGroups; }
            set { _deselectedUserGroups = value; }
        }

        #region ICloneable Members

        public virtual object Clone()
        {
            return new MediaFile(this);
        }

        #endregion

        public virtual string GetVirtualPath()
        {
            IList<string> path = new List<string>();
            MediaFolder f = _folder;

            // Create the path backwards, starting with the filename and up through the folder structure until the root media folder
            path.Add(_name);
            while (f != null)
            {
                path.Add(f.Name);
                f = f.Parent;
            }
            path.Add(_site.RootMediaFolder);
            string[] pathArray = path.ToArray();
            Array.Reverse(pathArray);
            return string.Join("/", pathArray);
        }

        public virtual string GetPhysicalPath()
        {
            return GetVirtualPath().Replace("/", "\\");
        }

        public virtual bool IsInCategory(string name)
        {
            if (_categories.Any(category => category.Name.ToLower() == name.ToLower()))
                return true;
            return _folder != null && _folder.IsInCategory(name);
        }
        
        public virtual IList<Category> GetAllCategories()
        {
            IList<Category> categories = _categories.ToList();
            if (_folder != null)
                foreach (Category c in _folder.GetAllCategories())
                    if (!categories.Contains(c))
                        categories.Add(c);
            return categories;
        }

        public virtual string[] GetCategoryNames()
        {
            return GetAllCategories().Select(pc => pc.Name).ToArray();
        }
        
        public virtual IList<UserGroup> GetRequiredUserGroups()
        {
            IList<UserGroup> groups = new List<UserGroup>();
            foreach (UserGroup group in _requiredUserGroups)
                groups.Add(group);
            if (_folder != null)
                foreach (UserGroup group in _folder.GetRequiredUserGroups())
                    if (!groups.Contains(group))
                        groups.Add(group);
            foreach (UserGroup group in _deselectedUserGroups)
                if (groups.Contains(group))
                    groups.Remove(group);
            return groups;
        }

        public virtual int CompareTo(MediaFile other)
        {
            return ID > 0 && ID == other.ID ? 0 : 1;
        }

        public virtual string GetState()
        {
            return "Name = " + _name +
                   ", Extension = " + _extension +
                   ", FolderID = " + (_folder != null ? _folder.ID.ToString() : "NULL") +
                   ", Path = " + GetVirtualPath() +
                   ", SortKey = " + _sortKey;
        }
    }
}